package com.yungu.swift.socket.communication.server;

import com.yungu.swift.socket.communication.server.channel.initializer.WebSocketChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * netty服务启动类
 * NettyServer
 *
 * @author cuixiuyin
 * @date 2018/11/22
 */

public class NettyServer {

    public static final Logger logger = LoggerFactory.getLogger(NettyServer.class);

    static int port = 0;

    private EventLoopGroup boss = null;
    private EventLoopGroup worker = null;
    private ServerBootstrap serverBootstrap = null;

    public static NettyServer nettyServer = null;

    public static NettyServer getInstance() {
        if (nettyServer == null) {
            synchronized (NettyServer.class) {
                if (nettyServer == null) {
                    nettyServer = new NettyServer();
                }
            }
        }
        return nettyServer;
    }

    /**
     * 绑定
     *
     * @throws InterruptedException
     */
    public void init() throws InterruptedException {
        try {
            //创建两个线程池
            //cuixiuyin 大小为 CPU 核心数
            boss = eventLoopGroup();
            worker = eventLoopGroup();

            serverBootstrap = new ServerBootstrap();
            //两个工作线程
            serverBootstrap.group(boss, worker);
            serverBootstrap.channel(channel());
            //GZL 2018-11-24 重用缓冲区
            serverBootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            serverBootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            //GZL 2018-11-24 自动调整下一次缓冲区建立时分配的空间大小，避免内存的浪费
            serverBootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT);
            //当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度,默认值50。
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            //用于启用或关于Nagle算法。如果要求高实时性，有数据发送时就马上发送，就将该选项设置为true关闭Nagle算法；如果要减少发送次数减少网络交互，就设置为false等累积一定大小后再发送。默认为false。
            //serverBootstrap.option(ChannelOption.TCP_NODELAY, true);
            //是否启用心跳保活机制
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            //支持webSocket协议
            serverBootstrap.childHandler(new WebSocketChannelInitializer());
            ChannelFuture f = serverBootstrap.bind(port == 0 ? 9999 : port).sync();
            if (f.isSuccess()) {
                logger.info("netty server start...");
            }
            //等到服务端监听端口关闭
            f.channel().closeFuture().sync();
        } finally {
            //优雅释放线程资源
            boss.shutdownGracefully().sync();
            worker.shutdownGracefully().sync();
        }
    }

    /**
     * EventLoopGroup 选择，Linux 系统选择 EpollEventLoopGroup
     *
     * @return
     */
    private EventLoopGroup eventLoopGroup() {
        String osName = System.getProperty("os.name");
        if (osName != null && osName.contains("Linux")) {
            return new EpollEventLoopGroup(Runtime.getRuntime().availableProcessors());
        }
        return new NioEventLoopGroup(Runtime.getRuntime().availableProcessors());
    }

    /**
     * 通道选择，Linux系统启用 EpollServerSocketChannel 通道
     *
     * @return
     */
    public Class<? extends ServerSocketChannel> channel() {
        String osName = System.getProperty("os.name");
        if (osName != null && osName.contains("Linux")) {
            return EpollServerSocketChannel.class;
        }
        return NioServerSocketChannel.class;
    }

}

